﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using UtilZ.Dotnet.Ex.Base;
using UtilZ.Dotnet.Ex.Log;
using UtilZ.Dotnet.Ex.DataStruct;

namespace WpfApp
{
    /// <summary>
    /// TestAsynQueue.xaml 的交互逻辑
    /// </summary>
    public partial class TestAsynQueue : Window
    {
        public TestAsynQueue()
        {
            InitializeComponent();
        }

        private long _value = 0;

        //private AsynQueueX<long> _asynQueue;
        private AsynQueueZ<long> _asynQueue;
        //private AsynQueue<long> _asynQueue;
        //private AsynQueueCore<long> _asynQueue;
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            var redirectAppenderToUI = (RedirectAppender)Loger.GetAppenderByName(null, "RedirectToUI");
            if (redirectAppenderToUI != null)
            {
                redirectAppenderToUI.RedirectOuput += RedirectLogOutput;
            }


            //this._asynQueue = new AsynQueue<long>(this.QueueCallback, new AsynQueueOptions() { ThreadName = "异步队列线程" });
            var options = new AsynQueueOptions()
            {
                BatchCount = 10000,
                BatchMillisecondsTimeout = 1000,
                Capcity = 10,
                FullMode = ContainerFullMode.DropOld
            };

            //this._asynQueue = new AsynQueueX<long>(this.QueueCallback2, options);
            this._asynQueue = new AsynQueueZ<long>(this.QueueCallback2, options);
            //this._asynQueue = new AsynQueue<long>(this.QueueCallback, options);
            //this._asynQueue = new AsynQueueCore<long>(this.QueueCallback2, options);
        }


        private void RedirectLogOutput(object sender, RedirectOuputArgs e)
        {
            //logControl.AddLog(e.Item.Content, e.Item.Level);

            string str;
            try
            {
                str = string.Format("{0} {1}", DateTime.Now.ToString("HH:mm:ss.fffffff"), e.Item.Content);
            }
            catch (Exception ex)
            {
                str = ex.Message;
            }

            logControl.AddLog(str, e.Item.Level);
        }

        private void QueueCallback2(long value, object tag)
        {
            Loger.Debug($"value:{value}");
        }
        private void QueueCallback(long value)
        {
            Loger.Debug($"value:{value}");
        }





        private void btnStart_Click(object sender, RoutedEventArgs e)
        {
            if (this._asynQueue.Status)
            {
                this._asynQueue.Stop();
                btnStart.Content = "Start";
            }
            else
            {
                this._asynQueue.Start();
                btnStart.Content = "Stop";
            }
        }

        private bool _flag = false;
        private void btnStartProduce_Click(object sender, RoutedEventArgs e)
        {
            if (_flag)
            {
                _flag = false;
                btnStartProduce.Content = "StartProduce";
            }
            else
            {
                _flag = true;
                btnStartProduce.Content = "StopProduce";

                var produceInterval = int.Parse(txtProduceInterval.Text);
                var addTimeout = int.Parse(txtAddTimeout.Text);
                var state = new Tuple<int, int>(produceInterval, addTimeout);

                //for (int i = 0; i < Environment.ProcessorCount - 1; i++)
                //{
                Task.Factory.StartNew(this.ProduceThreadMethod, state);
                //}
            }
        }

        private void ProduceThreadMethod(object obj)
        {
            var tp = (Tuple<int, int>)obj;
            int produceInterval2 = tp.Item1;
            int addTimeout2 = tp.Item2;

            Stopwatch stopwatch = new Stopwatch();
            int count = 1000;
            double[] times = new double[1000];
            int index = 0;
            double avg;

            while (_flag)
            {
                try
                {
                    stopwatch.Restart();
                    for (int i = 0; i < count; i++)
                    {
                        this._asynQueue.Enqueue(Interlocked.Increment(ref this._value));
                    }
                    stopwatch.Stop();

                    times[index] = stopwatch.Elapsed.TotalMilliseconds;
                    index++;
                    if (index >= times.Length)
                    {
                        avg = times.Average();
                        index = 0;

                        Loger.Info($"线程{Thread.CurrentThread.ManagedThreadId},统计{times.Length}次，添加{count}项平均耗时{avg}ms");
                    }
                }
                catch (Exception ex)
                {
                    Loger.Error(ex);
                }

                if (produceInterval2 > 0)
                {
                    //Thread.SpinWait(produceInterval2);
                    Thread.Sleep(produceInterval2);
                }
            }
        }

        private void btnClearLog_Click(object sender, RoutedEventArgs e)
        {
            logControl.Clear();
        }

        private void btnCount_Click(object sender, RoutedEventArgs e)
        {
            Loger.Info($"队列.Count:{this._asynQueue.Count}");
        }

        private void btnEnqueue_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                var value = this._value++;
                this._asynQueue.Enqueue(value);
                Loger.Info($"入队列\"{value}\",Count:{this._asynQueue.Count}");
            }
            catch (Exception ex)
            {
                Loger.Error(ex);
            }
        }

        private void btnDequeue_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                //var value = this._asynQueue.Dequeue();
                //Loger.Info($"出队列\"{value}\",Count:{this._asynQueue.Count}");
            }
            catch (Exception ex)
            {
                Loger.Error(ex);
            }
        }

        private void btnClarLog_Click(object sender, RoutedEventArgs e)
        {
            logControl.Clear();
        }

        private AsynQueue<TestAsynQueueItem> _asynQueueTest = null;
        private bool _runing = false;
        private long _consumerLength = 0L;
        private long _producerLength = 0L;
        private Queue<TestAsynQueueItem> _consumerQueue = new Queue<TestAsynQueueItem>();
        private void btnTest_Click(object sender, RoutedEventArgs e)
        {
            if (this._asynQueueTest == null)
            {
                var asynQueueOptions = new AsynQueueOptions()
                {
                    FullMode = ContainerFullMode.DropOld,
                    AutoStart = true,
                    Capcity = 1000
                };
                this._asynQueueTest = new AsynQueue<TestAsynQueueItem>(AsynQueueTestCallback, asynQueueOptions);
            }

            if (this._runing)
            {
                this._runing = false;
            }
            else
            {
                this._consumerLength = 0L;
                this._producerLength = 0L;
                this._consumerQueue.Clear();
                this._runing = true;
                Task.Factory.StartNew(Test);
            }
        }

        private void Test()
        {
            int producerCount = 100000;
            List<TestAsynQueueItem> removeItems;
            int removeCount = 0;
            for (int i = 0; i < producerCount; i++)
            {
                if (!this._runing)
                {
                    break;
                }

                var item = new TestAsynQueueItem();
                if (i % 2 == 0)
                {
                    item.Length = 2;
                }
                else
                {
                    item.Length = 4;
                }
                removeItems = this._asynQueueTest.Enqueue(item);
                this._producerLength += item.Length;

                if (removeItems != null)
                {
                    removeCount += removeItems.Count;
                }
            }

            while (this._asynQueueTest.Count > 0)
            {
                Thread.Sleep(10);
            }

            Loger.Info("完成");
            Loger.Info($"生产者长度:{this._producerLength}");
            Loger.Info($"消费者长度:{this._consumerLength}");
            Loger.Info($"生产者项数:{producerCount}");
            Loger.Info($"消费者项数:{this._consumerQueue.Count}");
            Loger.Info($"生产者移除项数:{removeCount},消费者总项数{this._consumerQueue.Count + removeCount}");

            this._runing = false;
        }


        private void AsynQueueTestCallback(TestAsynQueueItem item, object tag)
        {
            this._consumerLength += item.Length;
            this._consumerQueue.Enqueue(item);
        }


    }

    internal class TestAsynQueueItem
    {
        public int Length { get; set; }

        public string Name { get; set; }
    }
}
